﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
using BankCreditPortfolio.Attributes;
using BankCreditPortfolio.Models.ClientCabinetModels;
using BankCreditPortfolio.DAL;
using BankCreditPortfolio.DAL.Entities;
using BankCreditPortfolio.DAL.Services;
using MvcContrib.Pagination; 

namespace BankCreditPortfolio.Controllers
{
    [IsClient]
    public class ClientCabinetController : BaseController
    {
        //
        // GET: /ClientCabinet/ChangeDetails

        public ActionResult ChangeDetails()
        {
            var model = new ChangeDetailsModel();
            var profile = (new ClientService()).GetProfileByEmail(User.Identity.Name);

            model.MapFrom(profile);
            return View(model);
        }

        //
        // POST: /ClientCabinet/ChangeDetails

        [HttpPost]
        public ActionResult ChangeDetails(string button, ChangeDetailsModel model)
        {
            if (ModelState.IsValid)
            {
                var profile = (new ClientService()).GetProfileByEmail(User.Identity.Name);
                profile = model.MapTo(profile);

                try
                {
                    (new ProfileService()).Save(ref profile);
                    return RedirectToAction("Credits", "ClientCabinet");
                }
                catch (Exception ex)
                {
                    ModelState.AddModelError("", ex.InnerException.Message);
                }
            }
            return View(model);
        }


        //
        // GET: /ClientCabinet/Orders

        public ActionResult Orders(int? page)
        {
            var orders = (new OrderInfoService()).GetAllByEmail(User.Identity.Name);
            IEnumerable<OrderInfo> orderItems = orders != null ? orders.ToList() : new List<OrderInfo>();
            return View(orderItems.AsPagination(page ?? 1, 10));
        }

        //
        // GET: /ClientCabinet/Credits

        public ActionResult Credits(int? page)
        {
            var credits = (new AgreementService()).GetAllByEmail(User.Identity.Name);
            IEnumerable<Agreement> creditItems = credits != null ? credits.ToList() : new List<Agreement>();
            return View(creditItems.AsPagination(page ?? 1, 10));
        }

        //
        // GET: /ClientCabinet/CreditInfo

        public ActionResult CreditInfo(int agreementId, string message)
        {
            var model = new CreditInfoModel { Error = message };
            var agreement = (new AgreementService()).Find(agreementId);
            var order = agreement.Order;
            model.AgreementId = agreement.AgreementId;
            model.Currency = order.Currency.Title;
            model.GuarantorExists = order.Guarantors.Count > 0;
            if (model.GuarantorExists)
            {
                var guarantor = order.Guarantors.First().Profile;
                model.Guarantor = guarantor.FirstName + " " + guarantor.MiddleName + " " + guarantor.LastName;
            }
            model.TariffTitle = order.Tariff.Title;
            model.TariffId = order.Tariff.TariffId;
            return View(model);
        }

        public ActionResult NextPayments(int agreementId, string message)
        {
            var model = new NextPaymentsModel { Error = message };
            var agreement = (new AgreementService()).Find(agreementId);
            var order = agreement.Order;
            model.AgreementId = agreement.AgreementId;
            model.Currency = order.Currency.Title;
            model.TariffId = order.Tariff.TariffId;
            var amount = order.Amount * (1 + order.Tariff.CreditPercent * Convert.ToDecimal(0.01));
            var time = order.Tariff.Time;
            var first = order.Tariff.FirstPayment * amount / 100;
            var other = order.Tariff.OtherPayments * amount / 100;
            var period = (time.Year - 2000) * 365 + time.Month * 30;
            var requiredPaymentCount = Math.Round((amount - first) / other + Convert.ToDecimal(0.5)) + 1;
            var payments = (new PaymentService()).CreateQuery().Where(
                x => x.Deposit.DepositId == agreement.Credit.Deposit.DepositId);
            var paymentsCount = payments.Count();
            var nextPayment = agreement.Credit.DeliveryDate.AddDays
                (Convert.ToDouble(period / requiredPaymentCount) * (paymentsCount + 1));
            var previousPayment = agreement.Credit.DeliveryDate.AddDays
                (Convert.ToDouble(period / requiredPaymentCount) * (paymentsCount));
            model.Pay = previousPayment <= DateTime.Now;
            model.NextPayment = nextPayment.ToShortDateString();
            model.NextPaymentAmount = (new PaymentService()).GetAllByDepositId(agreement.Credit.Deposit.DepositId) == null ? first : other;
            model.Fine = nextPayment < DateTime.Now ? (DateTime.Now - nextPayment).Days * 
                Convert.ToDecimal(agreement.Order.Tariff.Fine * 0.01) * amount : 0;
            model.PrePaymentPenalty = model.NextPaymentAmount * agreement.Order.Tariff.EarlyRepaymentFine * Convert.ToDecimal(0.01);
            model.Amount = payments.Count() >= 1 ? (amount - (payments.Count() - 1) * other - first) : amount;
            model.PreRepayPenalty = model.Amount * agreement.Order.Tariff.EarlyRepaymentFine * Convert.ToDecimal(0.01);
            return View(model);
        }

        public ActionResult CreditPay(decimal amount, int agreementId)
        {
            var agreementService = new AgreementService();
            var agreement = agreementService.Find(agreementId);
            if (agreement.Credit.Deposit.Amount < amount)
            {
                return RedirectToAction("NextPayments", "ClientCabinet", new { agreementId, message = 
                                        "Payment could not be completed! Insufficient funds deposit" });
            }
            var payment = new Payment
                              {
                                  Currency = (agreement.Order.Currency),
                                  Amount = amount,
                                  Date = DateTime.Now,
                                  PaymentStatus = (new PaymentStatusService()).GetStatusByTitle("Waiting"),
                                  Deposit = agreement.Credit.Deposit
                              };
            (new PaymentService()).Save(ref payment);
            PaymentProcess();
            // last payment
            var payments = (new PaymentService()).GetAllByDepositId(payment.Deposit.DepositId);
            var tariff = agreement.Order.Tariff;
            var requiredCount =  (100 - tariff.FirstPayment) % tariff.OtherPayments == 0 ? (100 - tariff.FirstPayment) / tariff.OtherPayments + 1 :
                Math.Round((100 - tariff.FirstPayment) / tariff.OtherPayments + Convert.ToDecimal(0.5)) + 1;
            if (payments.Count() == requiredCount && payments.Sum(x => x.Amount) >= agreement.Order.Amount)
            {
                var orderInfoService = new OrderInfoService();
                var order = orderInfoService.Find(agreement.Order.OrderId);
                order.OrderStatus = (new OrderStatusService()).GetByTitle("Repayed");
                orderInfoService.Update(ref order);
                return RedirectToAction("Credits", "ClientCabinet");
            }
            return RedirectToAction("NextPayments", "ClientCabinet", new { agreementId });
        }

        public ActionResult CreditRepay(decimal amount, int agreementId)
        {
            var agreementService = new AgreementService();
            var agreement = agreementService.Find(agreementId);
            if (agreement.Credit.Deposit.Amount < amount)
            {
                return RedirectToAction("NextPayments", "ClientCabinet", new
                {
                    agreementId,
                    message =
                        "Payment could not be completed! Insufficient funds deposit"
                });
            }
            var payment = new Payment
            {
                Currency = (agreement.Order.Currency),
                Amount = amount,
                Date = DateTime.Now,
                PaymentStatus = (new PaymentStatusService()).GetStatusByTitle("Waiting"),
                Deposit = agreement.Credit.Deposit
            };
            (new PaymentService()).Save(ref payment);
            PaymentProcess();
            // last payment
                var orderInfoService = new OrderInfoService();
                var order = orderInfoService.Find(agreement.Order.OrderId);
                order.OrderStatus = (new OrderStatusService()).GetByTitle("Repayed");
                orderInfoService.Update(ref order);
                return RedirectToAction("Credits", "ClientCabinet");
        }

        public void PaymentProcess()
        {
            var paymentService = new PaymentService();
            var payments = paymentService.GetAllByStatus("Waiting");
            var depositService = new DepositService();
            foreach (var payment in payments)
            {
                var deposit = payment.Deposit;
                deposit.Amount -= payment.Amount;
                var bank = depositService.GetBankDeposit(payment.Currency.Title);
                bank.Amount += payment.Amount;
                depositService.Save(ref deposit);
                depositService.Save(ref bank);
                var paymentSave = payment;
                paymentSave.PaymentStatus = (new PaymentStatusService()).GetStatusByTitle("Received");
                paymentService.Save(ref paymentSave);
            }
        }

        //
        // GET: /ClientCabinet/DrawOrder

        [HttpGet]
        public ActionResult DrawOrder()
        {
            return View(new DrawOrderModel());
        }

        //
        // POST: /ClientCabinet/DrawOrder

        [HttpPost]
        public ActionResult DrawOrder(DrawOrderModel model, HttpPostedFileBase file)
        {
            var order = new OrderInfo();
            if ((new TariffService()).GetByTitle(model.TariffTitle).NumberOfGuarantors > 0)
            {
                model.GuarantorsRequired = true;
            }
            model.SelectedTariff = model.TariffTitle;
            model.ClientName = User.Identity.Name;
            if (file != null && (file.ContentLength <= 0 || file.ContentLength > 10*1024*1024))
            {
                ModelState.AddModelError("Documents", "You can not upload files more then 10 Mb");
            }
            if (ModelState.IsValid)
            {
                if (model.MapTo(order) != null)
                {
                    if (file != null && file.ContentLength > 0)
                    {
                        var fileName = Path.GetFileName(file.FileName);
                        var path = Server.MapPath("~/files/documents/") + User.Identity.Name + "/" + order.OrderId;
                        if (!(Directory.Exists(path)))
                            Directory.CreateDirectory(path);
                        path = Path.Combine(path, fileName);
                        file.SaveAs(path);
                        var documentPath = "/files/documents/" + User.Identity.Name + "/" + order.OrderId + "/" + fileName;
                        order.Documents = documentPath;
                        (new OrderInfoService()).Update(ref order);
                    }
                    return RedirectToAction("DrawOrderSuccess", "ClientCabinet");
                }
            }
            return View(model);
        }

        public ActionResult ShowAgreement(int agreementId)
        {
            var agreementService = new AgreementService();
            var agreement = agreementService.Find(agreementId);
            var model = new CreditAgreementModel().MapFrom(agreement);
            return View("CreditAgreement", model);
        }

        //
        // GET:  /ClientCabinet/DrawOrderSuccess

        public ActionResult DrawOrderSuccess()
        {
            return View();
        }      
    }


}
